// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: implementation of CImplItem.
//   $Id$

#include "stdafx.h"
#include "item.h"

#include "xforms.h"
#include "model.h"
#include "SelectUI.h"
#include "xformsxformselement.h"

#include "boundnode.h"
#include "resolvedItem.h"
#include "resolvedItemList.h"

#include "commonchild.h"
#include "choices.h"
#include "XFormsElementItem.h"
CImplItem::CImplItem()
	:m_pAlert(NULL)
	,m_pCaption(NULL)
	,m_pValue(NULL)
	,m_bRefreshing(false)
	,m_pResolvedItem(0)
	,m_bSelected(false)
{

}

CImplItem::CImplItem(CXFormsElementItem* pXFEl)
	:m_pAlert(NULL)
	,m_pCaption(NULL)
	,m_pValue(NULL)
	,m_bRefreshing(false)
	,m_pResolvedItem(0)
	,m_bSelected(false)
	,CFormControl(pXFEl)
{

}

CImplItem::~CImplItem()
{
	if(m_pModel)
		m_pModel->RemoveFormControl(this);
	
	if(m_pCaption)
		m_pCaption->m_pParent = 0;
	if(m_pValue)
		m_pValue->m_pParent = 0;

	if(m_pParent)
	{
		CImplSelection * pSel = dynamic_cast<CImplSelection *>(m_pParent);
		if(pSel)
			pSel->RemoveItem(this);
		else
		{
			CImplChoices * pChoices = dynamic_cast<CImplChoices *>(m_pParent);
			if(pChoices)
			{
				pChoices->RemoveItem(this);
			}
		}
	}
}

CImplSelection * CImplItem::GetOwnerSelection()
{
	ISelectionChild * pParent = dynamic_cast<ISelectionChild*>(m_pParent);
	if(pParent)
	{
		return pParent->GetOwnerSelection();
	}
	else
	{
		return dynamic_cast<CImplSelection *>(m_pParent);
	}
}

HRESULT CImplItem::refresh()
{
	FireStateEvents();
	//CImplItem has nothing of its own to refresh.
	return S_OK;
}

HRESULT CImplItem::onValueValueChange(BSTR sValue)
{
	//TODO:  Causes a refresh of the select.
	m_sValue = sValue;
	return S_OK;
}

HRESULT CImplItem::onCaptionValueChange(BSTR sCaption)
{
#ifdef OLD_SELECT_METHOD
	CImplSelection * pOwner = GetOwnerSelection();
	HRESULT hr = E_FAIL;
	if(pOwner)
	{
		pOwner->checkDrawn();
		CXFormsElementSelection * pOwnerSelectUI = static_cast<CXFormsElementSelection * >(pOwner->m_pXFormsElement);
		if(pOwnerSelectUI)
			hr = pOwnerSelectUI->put_ItemCaption(m_sId.m_str,sCaption);
		//Do not refresh as in onValueValueChange, the values of either control
		//	or item have not changed.
	}
	return hr;
#else
	HRESULT hr = S_FALSE;
	if(m_pResolvedItem)
		hr = m_pResolvedItem->put_label(sCaption);
	return hr;
#endif
}

HRESULT CImplItem::onAlertValueChange(BSTR sAlert)
{
#ifdef OLD_SELECT_METHOD
	HRESULT hr = E_FAIL;
	CImplSelection *pOwner = GetOwnerSelection();
	if(pOwner) {
		pOwner->checkDrawn();
		hr = ((CXFormsElementSelection *)pOwner->m_pXFormsElement)->put_ItemAlert(m_sId.m_str, sAlert);
	}
	return hr;
#else
	return S_OK;
#endif
}



HRESULT CImplItem::init(CImpl *pParent)
{
	if(!m_sId || m_sId == L"")
	{
		m_sId.Empty();

		//must have an id for internal purposes,
		//	it is not an error for this to be without 
		//	an id.
		//Generate an ID from the "this" pointer
		wchar_t sBuff[11];
		swprintf(sBuff,L"%X",(long)this);
		m_sId = sBuff;
		// CComBSTR(sBuff); // This results in the location of memory twice.
	}
//	return CImplSingleNodeBinding::init(pParent);
	return CFormControl::init(pParent);
}


HRESULT CImplItem::draw(BSTR const sDrawInside)
{
	HRESULT hr = E_FAIL;
	//insert the data.
	CImplSelection * pSel = GetOwnerSelection();
	if(pSel)
	{
		BSTR bs = ::SysAllocString(L" ");
		// HACK: Second m_sId is value. xf:select UI now returns a list of identifiers.
		hr = GetOwnerSelection()->drawItem(this, m_sId.m_str, bs, m_sId.m_str, sDrawInside, true);
		::SysFreeString(bs);
	}

	return hr;
}


HRESULT CImplItem::detachAlert(void)
{
	m_pAlert = 0;
	return S_OK;
}

HRESULT CImplItem::detachCaption(void)
{
	m_pCaption = 0;
	return S_OK;
}


void CImplItem::CreateResolvedCounterpart()
{
	//The simplest case, an item maintains a one-to-one relationship
	//	with a resolved item.
	CResolvedItemList * pList = dynamic_cast<IResolvedItemContainer*>(m_pParent)->GetResolvedItemList();
	if(pList)
	{
		m_pResolvedItem = pList->InsertNewItem(0,m_lIx);
	}
}


void CImplItem::SetSelectionIndex(long lIndex)
{
	m_lIx = lIndex;
}


void CImplItem::select(const long lIndex)
{
	//CImplItem should not be called with an
	//	index other than 0.  
	ASSERT(lIndex == 0);
	
	GetOwnerSelection()->appendValue(m_sValue);
	if(!m_bSelected)
	{
		FireEvent(EVENT_SELECTED);
		m_bSelected = true;
	}
}

void CImplItem::deselect()
{
	if(m_bSelected)
	{
		FireEvent(EVENT_DESELECTED);
		m_bSelected = false;
	}
}

void CImplItem::selectFrom(CList<VARIANT, VARIANT> &lstValues, CStringW &sList)
{
	POSITION pos = lstValues.GetHeadPosition();
	while(pos)
	{
		POSITION posTemp = pos;
		VARIANT v = lstValues.GetNext(pos);
		if(VT_BSTR == v.vt)
		{
			if(m_sValue == v.bstrVal)
			{
				lstValues.RemoveAt(posTemp);
				sList += m_sId;
				sList += " "; 
				::SysFreeString(v.bstrVal);
				break;
			}
		}
	}
}
